import is.glif.fenius.ws.draft.gen.ReservationParams;

import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.datatype.DatatypeFactory;
import org.ho.yaml.Yaml;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class FeniusDraftCreate extends HttpServlet {
    static String APOINT = "g-lambda.net:TOKYO";
    static String ZPOINT = "g-lambda.net:TSUKUBA";
    public static final long serialVersionUID = 01010102L;
    public final int MAX_ROUTE = 10;
    public final String IS_MENU = "true";
    public static int no = 55000;
    static String rtConfigFile = null;

    static public TimeZone timezone = TimeZone.getTimeZone("UTC");
    // static public TimeZone timezone = TimeZone.getTimeZone("JST");

    static public Hashtable<String, FeniusDraftDomain> domains = 
	new Hashtable<String, FeniusDraftDomain>();
    static public Hashtable<String, FeniusDraftClient> clients = 
	new Hashtable<String, FeniusDraftClient>();
    static public Hashtable<String, FeniusDraftDomain> endpoint2domain = 
	new Hashtable<String, FeniusDraftDomain>();
    static public Hashtable<String, String> endpoints = 
	new Hashtable<String, String>();
    static public Hashtable<String, String> endpoint2alias = 
	new Hashtable<String, String>();
    static public Hashtable<String, String> alias2endpoint = 
	new Hashtable<String, String>();
    static public Hashtable<String, String> errors = 
	new Hashtable<String, String>();
    static public Hashtable<String, String> apoints = 
	new Hashtable<String, String>();
    static public Hashtable<String, String> zpoints = 
	new Hashtable<String, String>();
    static public Hashtable<String, String> ids = 
	new Hashtable<String, String>();

    static {
	TimeZone.setDefault(timezone);
	// loadConfig("config.yml");
	// loadConfig("/home/okazaki/INSTALL/gridars3/java/nrm/test/feniusclient/config.yml");
	//loadConfig("/home/okazaki/fenius/trunk/fenius-translator-glambda/servlet/config.yml");
	loadConfig("/home/takano/fenius/fenius-translator-glambda/servlet/config.yml");
    }

    public FeniusDraftCreate() 
    {
    }

    public static synchronized String getString(Calendar c) {
	if (c == null) return null;

	String s = c.get(Calendar.YEAR)
	    + "/" + (c.get(Calendar.MONTH)+1)
	    + "/" + c.get(Calendar.DAY_OF_MONTH)
	    + " " + c.get(Calendar.HOUR_OF_DAY)
	    + ":" + c.get(Calendar.MINUTE)
	    + ":" + c.get(Calendar.SECOND);
	return s;
    }

    public static Calendar getCalendar()
    {
	Calendar calendar = Calendar.getInstance();
	calendar.setTime(new Date());
	calendar.set(Calendar.MILLISECOND, 0);
	return calendar;
    }

    private String head1 =
	"<html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"><link rel=\"stylesheet\" type=\"text/css\" href=\"/servlets/fenius.css\"><title>Fenius Reservation</title><body>";
    /*
    private String logo = 
	"<table width=\"96%\" align=center><TR><TD><img alt=\"G-lambda logo\" src=\"http://www.g-lambda.net/wordpress/wp-content/uploads/2006/10/the_g-lambda_logo_s.jpg\"></TD><TD><H1>Fenius/GNS-WSIv3 Reservation Creator</H1></TD></TABLE>\n";
    */
    private String logo = "<H1 align=center>Fenius Reservation Creator</H1>\n";

    private String tail = "</body></html>\n";
    String ap = APOINT;
    String zp = ZPOINT;
    Integer duration = new Integer(180);
    Integer bw = new Integer(1000);
    // Integer vlan = new Integer(100);

    // ResourceBundle rb = ResourceBundle.getBundle("LocalStrings");

    public synchronized void doGet(HttpServletRequest request,
                      HttpServletResponse response)
        throws IOException, ServletException
    {
	System.err.println("=========== doGet create start now\n");
	String s = head1 + logo;
	// s += "<H1 align=center>Fenius/G-lambda Reservation Creator</H1>\n";

	s += "<table width=\"96%\" align=\"center\" border=\"0\" cellpadding=\"5\">\n";
        s += "<form action=\"FeniusDraftCreate\" method=POST>";

	s += "<tr bgcolor=\"#C0C0C0\"><th>Reservation<BR>ID</th><th>Terminal<BR>Point</th><th>Terminal<BR>Point</th><th>Activate<BR>Time</th><th>Duration<BR>(sec)</th><th>BW<BR>(Mbps)</th><th>VLAN</th><th>SUBMIT</th></tr>\n";

	ReservationParams resvParams = null;
	String status = "Submitted";
	String rid = null;

	String do_create = null;
	String do_cancel = null;

	try {
	    String qid = request.getParameter("rid");
	    rid = qid;
	    String qap = request.getParameter("src");
	    ap = qap;
	    qap = alias2endpoint.get(qap);
	    String qzp = request.getParameter("dst");
	    zp = qzp;
	    qzp = alias2endpoint.get(qzp);

	    String qtime = request.getParameter("time");
	    String qduration = request.getParameter("duration");
	    String qbw = request.getParameter("bw");
	    String qvlan = request.getParameter("vlan");

	    do_create = request.getParameter("create");
	    do_cancel = request.getParameter("cancel");

	    if (rid != null) {
		s += "<td>" + qid + "</td>";
		s += "<td>" + ap + "</td>";
		s += "<td>" + zp + "</td>";
		s += "<td>" + qtime + "</td>";
		s += "<td>" + qduration + "</td>";
		s += "<td>" + qbw + "</td>";
		s += "<td>" + qvlan + "</td>";
	    }

	    errors.clear();
	    ids.clear();
	    apoints.clear();
	    zpoints.clear();

	    if (do_create == null) {
		doCancel(qap, qzp, qid);
		status = "Cancel";
	    } else if (do_cancel == null) {
		doCreate(qap, qzp, qid, qbw, qvlan, qtime, qduration);
		status = "Create";
	    } else {
		status = "Input Error";
	    }
	} catch (Exception ex) {
	    status = "Remote Error";
	    ex.printStackTrace();
	}

	if (rid != null) {
	    s += "<td>" + status + "</td>";
	    s += "</tr>\n";
	}
		
	/* GROUP_ID_POSOTION = 7 */
	rid = "R-" + no++;
	Calendar c = getCalendar();
	c.add(Calendar.MINUTE, 2);

	s += "<tr>";
	s += "<td> <input type=text name=rid value=\"" + rid + "\"/> </td>";

	String aselect = getMenu("src", ap);
	String zselect = getMenu("dst", zp);
	// s += "<td> <input type=text name=src size=30 value=\"" + ap + "\"/> </td>";
	// s += "<td> <input type=text name=dst size=30 value=\"" + zp + "\"/> </td>";
	s += "<td> " + aselect + "</td>";
	s += "<td> " + zselect + "</td>";

	s += "<td> <input type=text name=time size=30 value=\"" + 
	    getString(c) + "\"/> </td>";
	s += "<td> <input type=text name=duration size=6 value=\"" + duration + "\"/> </td>";
	s += "<td> <input type=text name=bw size=6 value=\"" + bw + "\"/> </td>";
	// s += "<td> <input type=text name=vlan size=6 value=\"" + vlan + "\"/> </td>";
	s += "<td>" + getVlanMenu() + " </td>";
	s += "<td> <input type=submit name=create value=CREATE /><input type=submit name=cancel value=CANCEL /> </td>";

	s += "</tr>\n";
	s += "</form></table>\n";

	if (do_create != null || do_cancel != null) {
	    s += "<table width=\"96%\" align=\"center\" border=\"0\" cellpadding=\"5\">\n";
	    s += "<tr bgcolor=\"#C0C0C0\"><th width=15%>Domain</th><th>Reservation<BR>ID</th><th>Terminal<BR>Point</th><th>Terminal<BR>Point</th><th>Result</th></tr>\n";

	    for( Enumeration e = errors.keys(); e.hasMoreElements(); ){
		String p = (String) e.nextElement();
		FeniusDraftDomain d = FeniusDraftCreate.domains.get(p);
		String display = d.getDisplayName();
		
		s += "<tr><td>" + display + "</td>\n";
		s += "<td>" + ids.get(p) + "</td>\n";
		s += "<td>" + endpoint2alias.get(apoints.get(p)) + "</td>\n";
		s += "<td>" + endpoint2alias.get(zpoints.get(p)) + "</td>\n";
		s += "<td>" + errors.get(p) + "</td></tr>\n";
	    }
	    s += "</table>\n";
	}

	s += tail;
	response.setContentType("text/html");

        PrintWriter out = response.getWriter();
        out.println(s);
	System.err.println("=========== doGet create end \n");
    }

    public String getVlanMenu() 
    {
	String r = "<select name=\"" + "vlan" + "\"> ";
	for( int i = 3103; i <= 3110; i++) {
	    if (i == 3105) {
		    r += "<option selected=\"selected\"> " + i + " </option> ";
	    } else {
		    r += "<option> " + i + " </option> ";
	    }
	}
	r += "</select>";
	return r;
    }

    public String getMenu(String name, String selected) 
    {
	String r = "<select name=\"" + name + "\"> ";
	for( Enumeration e = endpoints.keys(); e.hasMoreElements(); ){
	    String p = (String) e.nextElement();
	    String b = endpoints.get(p);
	    String alias = endpoint2alias.get(p);
	    if (IS_MENU.equals(b)) {
		if (p.equals(selected)) {
		    r += "<option selected=\"selected\"> " + alias + " </option> ";
		} else {
		    r += "<option> " + alias + " </option> ";
		}
	    }
	}
	// r += "<option> TEST-SITE </option> ";
	r += "</select>";
	System.err.println("select menu=" + r);
	return r;
    }

    public void doPost(HttpServletRequest request,
                      HttpServletResponse response)
        throws IOException, ServletException
    {
        doGet(request, response);
    }

    public boolean doCreate(String src, String dst, String id, String bw, String vlan,
			    String startTime, String duration)
    {
	if (src == null ||  dst == null || id == null || bw == null || vlan == null ||
	    bw == null ||  duration == null) return false;

	if (src.equals(dst)) return false;

	Calendar stime = null;
	String[] item = startTime.split("[:,.;/ ]+");
	if (item.length > 5) {
	    stime = getCalendar();
	    stime.set(Calendar.YEAR, Integer.parseInt(item[0]));
	    stime.set(Calendar.MONTH, Integer.parseInt(item[1]) -1);
	    stime.set(Calendar.DATE, Integer.parseInt(item[2]));
	    stime.set(Calendar.HOUR_OF_DAY, Integer.parseInt(item[3]));
	    stime.set(Calendar.MINUTE, Integer.parseInt(item[4]));
	    stime.set(Calendar.SECOND, Integer.parseInt(item[5]));
	    stime.setTimeZone(timezone);
	}
	
	boolean loop = true;
	Thread[] t = new Thread[MAX_ROUTE];

	for(int i = 0; i < MAX_ROUTE && loop; i++) {
	    String ksrc = src;
	    FeniusDraftDomain srcd = endpoint2domain.get(ksrc);
	    FeniusDraftDomain dstd = endpoint2domain.get(dst);
	    if (srcd == null || dstd == null) return false;
	    
	    String newdst = dst;
	    FeniusDraftRoute r = null;
	    if (srcd != dstd) {
		r = srcd.getRoute(dstd.getName());
		if (r == null) return false;
		newdst = r.getNexthop();
	    } else {
		loop = false;
	    }
	    if (loop) src = r.getConnect();

	    final String domainName = srcd.getName();
	    final FeniusDraftClient client = clients.get(domainName);
	    if (client == null) {
		errors.put(domainName, "Fenius Translator is null.");
		continue;
	    }
		
	    final String rid = new String(id) + "[" + i + "]";
	    final Calendar rtime = (Calendar) stime.clone();
	    final Integer rduration = new Integer(duration);
	    final Integer rbw = new Integer(bw);
	    // final Integer rvlan = new Integer(vlan) + i; /* for NRM only */
	    final Integer rvlan = new Integer(vlan);
	    final String rsrc = new String(ksrc);
	    final String rdst = new String(newdst);
	    final Hashtable<String, String> e = errors;
	    
	    System.err.println("reserve:" + ksrc + "->" + rdst + ", vlan" + rvlan);

	    ids.put(domainName, rid);
	    apoints.put(domainName, ksrc);
	    zpoints.put(domainName, rdst);

	    /*
	    t[i] = new Thread(new Runnable() 
		{
		    public void run()
		    {
			System.err.println("tread reserve:" + rsrc + "->" + rdst);
			try {
			    client.doCreate(rid, rtime, rduration, rbw, rvlan, 
					    rsrc, rdst);
			    errors.put(domainName., "Success.");
			} catch (Exception ex) {
			    ex.printStackTrace();
			    e.put(domainName, ex.toString());
			}
		    }
		});
	    
	    t[i].start();
	    */

	    try {
		client.doCreate(rid, rtime, rduration, rbw, rvlan, rsrc, rdst);
		errors.put(domainName, "Success.");
	    } catch (Exception ex) {
		ex.printStackTrace();
		errors.put(domainName, ex.toString());
	    }

	    // System.err.println("next apoint:" + src);
	}

	for(int i = 0; i < MAX_ROUTE; i++) {
	    try {
		if (t[i] != null) t[i].join();
	    } catch (Exception ex) {
		ex.printStackTrace();
	    }
	}
	return true;
    }

    public boolean doCancel(String src, String dst, String id)
    {
	if (src == null ||  dst == null || id == null) return false;
	if (src.equals(dst)) return false;

	boolean loop = true;
	Thread[] t = new Thread[MAX_ROUTE];

	for(int i = 0; i < MAX_ROUTE && loop; i++) {
	    String ksrc = src;
	    FeniusDraftDomain srcd = endpoint2domain.get(ksrc);
	    FeniusDraftDomain dstd = endpoint2domain.get(dst);
	    if (srcd == null || dstd == null) return false;
	    
	    String newdst = dst;
	    FeniusDraftRoute r = null;
	    if (srcd != dstd) {
		r = srcd.getRoute(dstd.getName());
		if (r == null) return false;
		newdst = r.getNexthop();
	    } else {
		loop = false;
	    }
	    if (loop) src = r.getConnect();

	    final String domainName = srcd.getName();
	    final FeniusDraftClient client = clients.get(domainName);
	    if (client == null) {
		errors.put(domainName, "Fenius Translator is null.");
		continue;
	    }
	    
	    final String rid = id + "[" + i + "]";
	    System.err.println("cancel:" + ksrc + "->" + newdst);
	    ids.put(domainName, id);
	    apoints.put(domainName, ksrc);
	    zpoints.put(domainName, newdst);
	    
	    /*
	    t[i] = new Thread(new Runnable() 
		{
		    public void run()
		    {
			try {	
			    client.doCancel(rid);
			} catch (Exception ex) {
			    ex.printStackTrace();
			    errors.put(domainName, ex.toString());
			}
		    }
		});
	    
	    t[i].start();
	    */

	    try {
		client.doCancel(rid);
		errors.put(domainName, "Success.");
	    } catch (Exception ex) {
		ex.printStackTrace();
		errors.put(domainName, ex.toString());
	    }
	}

	for(int i = 0; i < MAX_ROUTE; i++) {
	    try {
		if (t[i] != null) t[i].join();
	    } catch (Exception ex) {
		ex.printStackTrace();
	    }
	}
	return true;
    }

    @SuppressWarnings({ "static-access", "unchecked" })
    static public void loadConfig(String config)
    {
	try {
	    if (config == null) {
		throw new ServletException("Config file name is null.");
	    }
	    System.err.println("=========== config:" + config);
	    String configFile = config;

	    InputStream propFile = new FileInputStream(configFile);
	    Map baseConfig = (Map) Yaml.load(propFile);
	    FeniusClientConfig clientConfig = new FeniusClientConfig();

	    rtConfigFile = (String) baseConfig.get("config");
	    Map rtConfig = (Map) Yaml.load(new FileInputStream(rtConfigFile));
	    Integer lastRsrvId = (Integer) rtConfig.get("lastRsrvId");
	    if (lastRsrvId != null)
		    no = lastRsrvId.intValue() + 10;

	    ArrayList<Map> servicesConfig =
		(ArrayList<Map>) baseConfig.get("fenius-services");
	    for (Map serviceConfig : servicesConfig) {
		String url = (String) serviceConfig.get("url");
		clientConfig.setUrl(url);
		clientConfig.setUseSSL((Boolean) serviceConfig.get("useSSL"));
		clientConfig.setSslKeystorePath((String) serviceConfig.get("sslKeystorePath"));
		clientConfig.setSslKeystorePass((String) serviceConfig.get("sslKeystorePass"));
		clientConfig.setSslTruststorePath((String) serviceConfig.get("sslTruststorePath"));
		clientConfig.setSslTruststorePass((String) serviceConfig.get("sslTruststorePass"));
		clientConfig.setUseBasicHttpAuth((Boolean) serviceConfig.get("useBasicHttpAuth"));
		clientConfig.setHttpUsername((String) serviceConfig.get("httpUsername"));
		clientConfig.setHttpPassword((String) serviceConfig.get("httpPassword"));

		String domain = (String) serviceConfig.get("domain");
		String display = (String) serviceConfig.get("domain_d");
		String user = (String) serviceConfig.get("user");
		String password = (String) serviceConfig.get("password");

		try {
		    FeniusDraftClient cli = new FeniusDraftClient(clientConfig);
		    clients.put(domain, cli);
		} catch (Exception e) {}
		FeniusDraftDomain fdd = new FeniusDraftDomain(domain, url, display);
		domains.put(domain, fdd);
		
		ArrayList<Map> endpointsConfig =
		    (ArrayList<Map>) serviceConfig.get("endpoint");
		for (Map endpointConfig : endpointsConfig) {
		    String endpoint = (String) endpointConfig.get("identifier");
		    String ismenu = (String) endpointConfig.get("menu");
		    String alias = (String) endpointConfig.get("display");
		    // System.err.println("=========== config:endpoint=" + endpoint);
		    // System.err.println("=========== config:ismenu=" + ismenu);
		    fdd.addEndpoint(endpoint);
		    endpoint2domain.put(endpoint, fdd);
		    endpoints.put(endpoint, ismenu);
		    endpoint2alias.put(endpoint, alias);
		    alias2endpoint.put(alias, endpoint);
		}

		ArrayList<Map> routesConfig =
		    (ArrayList<Map>) serviceConfig.get("route");
		for (Map routeConfig : routesConfig) {
		    String destination = (String) routeConfig.get("destination");
		    // System.err.println("=========== config:destination=" + destination);
		    
		    String nexthop = (String) routeConfig.get("nexthop");
		    String nextconnect = (String) routeConfig.get("connect");

		    FeniusDraftRoute r = new FeniusDraftRoute
			(domain, destination, nexthop, nextconnect);
		    fdd.addRoute(r);
		}
	    }
	} catch (Exception ex) {
	    System.err.println("=========== config: error");
	    ex.printStackTrace();
	}
    }

    public String getConfig() 
    {
	String s = "";

	for( Enumeration e = domains.elements(); e.hasMoreElements(); ){
	    FeniusDraftDomain domain = (FeniusDraftDomain) e.nextElement();
	    s += domain.toString();
	}
	return s;
    }

    public void destroy()
    {
	if (rtConfigFile == null) return;

	Hashtable<String, Integer> rtConfig = new Hashtable<String, Integer>();
	rtConfig.put("lastRsrvId", new Integer(no));
	try {
	    Yaml.dump(rtConfig, new File(rtConfigFile));
	} catch (FileNotFoundException ex) {
	    System.err.println("WARN: Can not open the config file: \"" + rtConfigFile + "\"");
	}
    }

    static public void main(String[] args)
    {
	FeniusDraftCreate c = new FeniusDraftCreate();
	System.err.println(c.getConfig());

	try {
	    if (true) {
		Calendar t = getCalendar();
		t.add(Calendar.MINUTE, 1);
		// String src = "g-lambda.net:TSUKUBA";
		String src = "kreonet.re.kr:aaaa";
		// String src = "g-lambda.net:AKIBA";
		// String src = "startap.net:e1200:te1/0";
		// String dst = "ist-phosphorus.eu:zzzz";
		// String dst = "g-lambda.net:CHICAGO";
		String dst = "g-lambda.net:TSUKUBA";
		// String dst = "startap.net:e1200:te1/1";
		c.doCreate(src, dst, "TESTA7", "1000", "280", getString(t), "60"); 
		//System.err.println("");
		//c.doCreate(dst, src, "TEST-2", "1000", "101", getString(t), "120"); 
		//System.err.println("");
	    
		//c.doCancel(src, dst, "TEST-1");
		//System.err.println("");
		//c.doCancel(dst, src, "TEST-2");
		//System.err.println("");
	    
		// src = "kreonet.re.kr:aaaa";
		// dst = "kreonet.re.kr:aaaa";
		// c.doCreate(src, dst, "ATEST-3", "1000", "231", getString(t), "120"); 
		//System.err.println("");
		//c.doCreate(dst, src, "ATEST-4", "1000", "201", getString(t), "120"); 
		//System.err.println("");
	    
		//c.doCancel(src, dst, "TEST-3");
		//System.err.println("");
		//c.doCancel(dst, src, "TEST-4");
		//System.err.println("");
	    }
	    // c.getMenu("test", "g-lambda.net:OSAKA");
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
    }
}
